import { DBManager } from "mvx-foundation";
import { Async, Millisecond } from "mvx-utils";
class WXStorage {
    constructor() {
        this.cache_ = new Map([]);
        if (uni.canIUse("onAppHide")) {
            uni.onAppHide(async () => {
                for (let [table, { timerId }] of this.savingTimer) {
                    await this.saveToStorage(table);
                    clearTimeout(timerId);
                }
                this.savingTimer.clear();
            });
        }
    }
    async loadFromStorage(table) {
        if (this.cache_.has(table)) {
            return this.cache_.get(table);
        }
        if (!this.loadWaiting.has(table)) {
            this.loadWaiting.set(table, []);
        }
        return new Promise(resolve => {
            const waiting = this.loadWaiting.get(table);
            waiting.push(resolve);
            if (waiting.length > 1) {
                return;
            }
            Async(async () => {
                try {
                    const ret = await uni.getStorageSync(encodeURIComponent(table));
                    const map = new Map(ret.data);
                    this.cache_.set(table, map);
                }
                catch (e) {
                    this.cache_.set(table, new Map([]));
                }
                for (let r of waiting) {
                    r(this.cache_.get(table));
                }
                this.loadWaiting.set(table, []);
            });
        });
    }
    async saveToStorage(table) {
        try {
            const map = await this.loadFromStorage(table);
            await uni.setStorageSync(encodeURIComponent(table), Array.from(map.entries()));
            return null;
        }
        catch (e) {
            return new Error("failed");
        }
    }
    async get(table, key) {
        const map = await this.loadFromStorage(table);
        if (map.has(key)) {
            return [map.get(key), null];
        }
        return ["", new Error(`not found`)];
    }
    async getAllKeys(table) {
        const map = await this.loadFromStorage(table);
        const keys = [];
        for (let [key, _] of map) {
            keys.push(key);
        }
        return keys;
    }
    async remove(table, key) {
        const item = await this.loadFromStorage(table);
        item.delete(key);
        return await this.saveToStorage(table);
    }
    async set(table, key, value) {
        const item = await this.loadFromStorage(table);
        item.set(key, value);
        if (this.savingTimer.has(table)) {
            clearTimeout(this.savingTimer.get(table).timerId);
            this.savingTimer.delete(table);
        }
        const timerId = setTimeout(async () => {
            await this.saveToStorage(table);
            this.savingTimer.delete(table);
        }, 100 * Millisecond);
        this.savingTimer.set(table, { timerId: timerId });
        return null;
    }
    loadWaiting = new Map([]);
    cache_;
    savingTimer = new Map([]);
}
export class WXDBManager extends DBManager {
    newSessionStorage() {
        return new WXStorage();
    }
    newLocalStorage() {
        return new WXStorage();
    }
}
